﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Ionic.Zip;
using ResxHelper.Logic.Actions;
using ResxHelper.Logic.Readers;
using ResxHelper.Object;

namespace ResxHelper.Logic.Converter
{
    public class ConvertBulkAndroid : IBulkConvert
    {
        public void ToExcel(string inputPath, string outputPath)
        {
            // create temp directory
            var directoryName = string.Format("{0}{1}", Path.GetTempPath(), Guid.NewGuid());
            var tempDirectory = Directory.CreateDirectory(directoryName);

            // unpack the zip to temp directory
            using (var zip = ZipFile.Read(inputPath))
            {
                foreach (var entry in zip)
                {
                    entry.Extract(tempDirectory.FullName, ExtractExistingFileAction.OverwriteSilently);
                }
            }

            // read all of the resource files
            var resourceFiles = ReadFiles(tempDirectory.FullName);

            // convert each file to an excel file
            var paths = SaveTempExcelFiles(tempDirectory.FullName, resourceFiles);

            // create a new zip
            var zipRequest = new SaveZipRequest(paths, outputPath, true);
            SaveActionInvoker.Save(zipRequest, SaveFileType.Zip, outputPath);

            // delete the temp directory
            Directory.Delete(tempDirectory.FullName, true);
        }

        public void ToResource(string inputPath, string outputPath)
        {
            // create temp directory
            var directoryName = string.Format("{0}{1}", Path.GetTempPath(), Guid.NewGuid());
            var tempDirectory = Directory.CreateDirectory(directoryName);

            // unpack the zip to temp directory
            using (var zip = ZipFile.Read(inputPath))
            {
                foreach (var entry in zip)
                {
                    entry.Extract(tempDirectory.FullName, ExtractExistingFileAction.OverwriteSilently);
                }
            }

            // read all files to resource files
            var resourceFiles = ReadExcelFiles(tempDirectory.FullName);

            // make converstion and create structure
            var savedDirectory = SaveToStructure(tempDirectory.FullName, resourceFiles);

            // save zip
            SaveZipDirectory(outputPath, savedDirectory);

            // cleanup
            Directory.Delete(tempDirectory.FullName, true);

            // open the folder 
            // TODO: this shouldn't be here
            //Process.Start("explorer.exe", string.Format("/select, {0}", outputPath));
        }

        private static IEnumerable<ResourceFile> ReadFiles(string tempFilePath)
        {
            // perform the read
            var resourceFiles = new List<ResourceFile>();

            // recursively find all directories that contain a directory called res
            var resourceDirectories = FindResourceDirectories(tempFilePath);

            foreach (var directory in resourceDirectories)
            {
                resourceFiles.AddRange(ReadResourcesFromDirectory(directory));
            }

            return resourceFiles;
        }

        private static IEnumerable<string> FindResourceDirectories(string path)
        {
            var resourceDirectories = new List<string>();
            foreach (var dir in Directory.GetDirectories(path))
            {
                var resourceDir = string.Format("{0}\\res", dir);
                if(Directory.Exists(resourceDir))
                {
                    resourceDirectories.Add(resourceDir);
                }

                resourceDirectories.AddRange(FindResourceDirectories(dir));
            }
            return resourceDirectories;
        } 

        private static IEnumerable<ResourceFile> ReadResourcesFromDirectory(string path)
        {
            var resourceFiles = new List<ResourceFile>();
            foreach (var resourceDir in Directory.GetDirectories(path)
                .Where(d => d.Contains("values")))
            {
                foreach (var resourceFile in Directory.GetFiles(resourceDir))
                {
                    if (Path.GetExtension(resourceFile) == ".xml")
                    {
                        var reader = new AndroidResourceFileReader(resourceFile);
                        resourceFiles.Add(reader.Read());
                    }
                }
            }
            return resourceFiles;
        }

        private static IEnumerable<string> SaveTempExcelFiles(string tempPath, IEnumerable<ResourceFile> files)
        {
            var newFilePaths = new List<string>();
            foreach (var file in files)
            {
                var newFileName = GetExportFileName(tempPath, file.FilePath);
                var newFilePath = string.Format("{0}\\{1}", tempPath, newFileName);
                SaveActionInvoker.Save(file, SaveFileType.Excel, newFilePath);
                newFilePaths.Add(newFilePath);
            }
            return newFilePaths.ToArray();
        }

        private static string GetExportFileName(string tempDirectory, string tempFilePath)
        {
            var actualPath = tempFilePath.Replace(string.Format("{0}\\", tempDirectory), string.Empty);
            var pathSplit = actualPath.Split('\\');
            
            var fileName = Path.GetFileNameWithoutExtension(tempFilePath);

            int offset = 0;
            if (pathSplit[0] == "_brands")
            {
                offset = 1;
            }

            var scope = pathSplit[0 + offset];

            // locale
            var localeSplit = pathSplit[2 + offset].Split('-');
            string localeString = localeSplit.Count() > 1 ? localeSplit[1 + offset] : "en";
            
            var newFileName = string.Format("{0}-{1}.{2}.{3}",
                scope,
                fileName,
                localeString,
                "xls");

            if (offset == 1) newFileName = string.Format("{0}#{1}", pathSplit[0], newFileName);
            return newFileName;
        }

        private static string SaveToStructure(string tempDirectory, IEnumerable<ResourceFile> files)
        {
            var structuredFolder = string.Format("{0}\\{1}", tempDirectory, "AndroidResources");
            var newStructure = Directory.CreateDirectory(structuredFolder);

            foreach (var file in files)
            {
                var androidFilePath = GetPathFromFileName(file.GetFileNameWithoutExtension());
                var saveDirectoryPath = string.Format("{0}\\{1}", newStructure.FullName,
                    Path.GetDirectoryName(androidFilePath));
                var saveFilePath = string.Format("{0}\\{1}", newStructure.FullName, androidFilePath);

                if (!Directory.Exists(saveDirectoryPath)) Directory.CreateDirectory(saveDirectoryPath);

                SaveActionInvoker.Save(file, SaveFileType.AndroidResource, saveFilePath);
            }

            return newStructure.FullName;
        }

        private static string GetPathFromFileName(string fileName)
        {
            // subdir#scope-filename.locale.xls
            var directorySplit = fileName.Split('#');
            
            int offset = 0;
            if (directorySplit.Count() > 1) offset = 1;

            if(offset > 0) fileName = directorySplit[1];

            var scopeSplit = fileName.Split('-');
            var scope = scopeSplit[0];

            var fileNameSplit = scopeSplit[1].Split('.');
            var actualFileName = fileNameSplit[0] + ".xml";
            var locale = fileNameSplit.Count() > 1 ? "-" + fileNameSplit[1] : string.Empty;
            if (locale.ToLower().Contains("en")) locale = string.Empty;

            var subdir = offset > 0 ? string.Format("{0}\\", directorySplit[0]) : string.Empty;
            var directory = string.Format("{0}{1}\\res\\values{2}\\{3}", subdir, scope, locale, actualFileName);
            return directory;
        }

        private static IEnumerable<ResourceFile> ReadExcelFiles(string tempDirectory)
        {
            var resourceFiles = Directory.GetFiles(tempDirectory)
                .Where(f => Path.GetExtension(f) == ".xls")
                .Select(file => ResourceFileReaderFactory
                    .GetReader(file, ResourceType.Excel))
                    .Select(reader => reader.Read())
                    .ToList();

            return resourceFiles;
        }

        private static void SaveZipDirectory(string savePath, string folderLocation)
        {
            using (var zip = new ZipFile())
            {
                zip.AddDirectory(folderLocation);
                zip.Save(savePath);
            }
        }
    }
}
